
import com.itextpdf.text.BadElementException;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.BarcodeQRCode;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfDate;
import com.itextpdf.text.pdf.PdfDictionary;
import com.itextpdf.text.pdf.PdfName;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfSignature;
import com.itextpdf.text.pdf.PdfSignatureAppearance;
import com.itextpdf.text.pdf.PdfStamper;
import com.itextpdf.text.pdf.PdfString;
import integrisign.IDocInfo;
import integrisign.desktop.Base64Format;
import integrisign.desktop.DeskSign;
import integrisign.desktop.ValidationException;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.util.Calendar;
import java.util.HashMap;



/*
 * Esto será una clase de prueba para adjuntar la firma recogida desde un ePadInk
 * y se añadirá a un PDF
 */

/**
 * @since 12/02/2013
 * @author epindado
 */
public class firmaPDFNueva implements IDocInfo {
    
    /**
     * Función principal
     * @param args 
     */
    public static void main(String[] args) {
        // Incializamos el objeto que controla ePadInk
        DeskSign deskSign = new DeskSign();   
        firmaPDFNueva firmapdf = new firmaPDFNueva();
        
        //Se vacía el objeto
        deskSign.clear();
        //Iniciar lector
        firmapdf.iniciarLector("Eduardo", deskSign);

        System.out.println("Firma: " + deskSign.getString());

        //Grabar imagen
        firmapdf.insertarImagen("C:\\usando-google-code.pdf","C:\\usando-google-code.Imagen.pdf",deskSign);

        //Firma Digital
        firmapdf.firmaDigitalPDF("C:\\usando-google-code.Barcode.pdf", "C:\\usando-google-code.Signed.pdf",
                ".\\keystore\\keystore.ks");

        //Grabar barcode
        firmapdf.insertaBarCode("C:\\usando-google-code.Imagen.pdf", "C:\\usando-google-code.Barcode.pdf", deskSign);
            
        System.exit(0);
    }
    
    /**
     * Método para lanzar el lector
     * @param usuario
     * @param deskSign
     * @throws ValidationException 
     * 
     */
    private void iniciarLector (String usuario, DeskSign deskSign) {
        try {
            /**
             * signNow(stringID, stringname, stringdesg, stringorg, stringAddr, 
             * stringFooter,  stringreserved,  booleanbreserved1, booleanshowOptions, 
             * booleanbreserved2, integrisign.IdocInfoidinfo)
             */
            deskSign.signNowEx(usuario, "", "", "", "", true, (IDocInfo)this);
        } catch (ValidationException ex) {
            ex.printStackTrace();
            //Logger.getLogger(firmaPDFNueva.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
    /**
     * Método encargado de guardar la imagen en un pdf
     * @param deskSign
     */
    private void insertarImagen (String rutaEntrada, String rutaSalida, DeskSign deskSign) {
        PdfReader reader = null;
        PdfStamper stamper = null;
        try {
            reader = new PdfReader(rutaEntrada);
            stamper = new PdfStamper(reader, new FileOutputStream(rutaSalida));
            
            String signstr = deskSign.getString();
            Base64Format b64fmt = new Base64Format();
            byte[] jpegbytes = b64fmt.decode64(deskSign.getJpegString(signstr, 100, 65, 100));
            Image img = Image.getInstance(jpegbytes);
            /**
             * TODO Posición absoluta
             */
            img.setAbsolutePosition(250f, 40f);

            int maxPagina = reader.getNumberOfPages();
            PdfContentByte underContent = stamper.getUnderContent(maxPagina);
            underContent.addImage(img);
           
        } catch (BadElementException ex) {
            ex.printStackTrace();
            //Logger.getLogger(firmaPDF.class.getName()).log(Level.SEVERE, null, ex);
        } catch (MalformedURLException ex) {
            ex.printStackTrace();
            //Logger.getLogger(firmaPDF.class.getName()).log(Level.SEVERE, null, ex);
        } catch (DocumentException ex) {
            ex.printStackTrace();
            //Logger.getLogger(firmaPDF.class.getName()).log(Level.SEVERE, null, ex);
        } catch (FileNotFoundException ex) {
            ex.printStackTrace();
            //Logger.getLogger(firmaPDF.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            ex.printStackTrace();
            //Logger.getLogger(firmaPDF.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                if (stamper != null){
                    try {
                        stamper.close();
                    } catch (DocumentException ex) {
                        ex.printStackTrace();
                    }
                }
                if (reader != null){
                    reader.close();
                }
            } catch (IOException ex) {
                ex.printStackTrace();
                //Logger.getLogger(firmaPDF.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
    
   /**
    * Método encargado de insertar una imagen generada de un código de barras
    * @param rutaEntrada
    * @param rutaSalida
    * @param deskSign 
    */ 
   private void insertaBarCode (String rutaEntrada, String rutaSalida, DeskSign deskSign){
        PdfReader reader = null;
        PdfStamper stamper = null;
        try {
            reader = new PdfReader(rutaEntrada);
            stamper = new PdfStamper(reader, new FileOutputStream(rutaSalida));
            
            int maxPagina = reader.getNumberOfPages();
            PdfContentByte underContent = stamper.getUnderContent(maxPagina);
            
            // Inserción código de barras
            BarcodeQRCode codeQR = new BarcodeQRCode(deskSign.getString(), 0, 0, null);
            Image imageEAN = codeQR.getImage();
            imageEAN.setAbsolutePosition(100f, 5f);
            underContent.addImage(imageEAN);
            
        } catch (BadElementException ex) {
            ex.printStackTrace();
            //Logger.getLogger(firmaPDF.class.getName()).log(Level.SEVERE, null, ex);
        } catch (MalformedURLException ex) {
            ex.printStackTrace();
            //Logger.getLogger(firmaPDF.class.getName()).log(Level.SEVERE, null, ex);
        } catch (DocumentException ex) {
            ex.printStackTrace();
            //Logger.getLogger(firmaPDF.class.getName()).log(Level.SEVERE, null, ex);
        } catch (FileNotFoundException ex) {
            ex.printStackTrace();
            //Logger.getLogger(firmaPDF.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            ex.printStackTrace();
            //Logger.getLogger(firmaPDF.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                if (stamper != null){
                    try {
                        stamper.close();
                    } catch (DocumentException ex) {
                        ex.printStackTrace();
                    }
                }
                if (reader != null){
                    reader.close();
                }
            } catch (IOException ex) {
                ex.printStackTrace();
                //Logger.getLogger(firmaPDF.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
   }
    
    /**
     * Método encargado de realizar la firma de un pdf
     * @param rutaEntrada
     * @param rutaSalida
     * @param rutaFirma 
     */
    private void firmaDigitalPDF (String rutaEntrada, String rutaSalida, String rutaFirma){
        PdfReader reader = null;
        PdfStamper stamper = null;
        try {
            KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
            ks.load(new FileInputStream(rutaFirma), "password".toCharArray());
            String alias = (String)ks.aliases().nextElement();
            PrivateKey key = (PrivateKey)ks.getKey(alias, "password".toCharArray());
            Certificate[] chain = ks.getCertificateChain(alias);
            reader = new PdfReader(rutaEntrada);
            FileOutputStream fout = new FileOutputStream(rutaSalida);
            stamper = PdfStamper.createSignature(reader, fout, '\0');
            
            PdfSignatureAppearance sap = stamper.getSignatureAppearance();
            sap.setReason("Soy el autor");
            sap.setLocation("Madrid");
            //Se hace visible la firma
            int maxPagina = reader.getNumberOfPages();
            sap.setVisibleSignature(new Rectangle(100, 150, 200, 200), maxPagina, null);
            
            PdfSignature sigDic = new PdfSignature(PdfName.ADOBE_PPKLITE,PdfName.ADBE_PKCS7_DETACHED);
            sigDic.put(PdfName.FT, PdfName.SIG);
            sigDic.put(PdfName.M, new PdfDate(Calendar.getInstance()));
            sap.setCryptoDictionary(sigDic);
            HashMap exclusions = new HashMap();
            exclusions.put(PdfName.CONTENTS, 4);
            sap.preClose(exclusions);
            
            PdfDictionary updates = new PdfDictionary();
            byte out[] = new byte[2];
            updates.put(PdfName.CONTENTS, new PdfString(out));
            sap.close(updates);
             
            /** digital signature
            * TODO Con proveedor local dice no such provider BC
            * TODO Si no se añaden estas lineas no serán necesarias las librerias:
            *   bcprov-jdk15on-148.jar
            *   bcpkix-jdk15on-148.jar
            * ExternalSignature es = new PrivateKeySignature(key, "SHA-256", "BC");
            * ExternalDigest digest = new BouncyCastleDigest();
            * MakeSignature.signDetached(sap, digest, es, chain, null, null, null, 0, CryptoStandard.CMS);
            */
        } catch (DocumentException ex) {
            ex.printStackTrace();
            //Logger.getLogger(firmaPDFNueva.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnrecoverableKeyException ex) {
            ex.printStackTrace();
            //Logger.getLogger(firmaPDF.class.getName()).log(Level.SEVERE, null, ex);
        } catch (NoSuchAlgorithmException ex) {
            ex.printStackTrace();
            //Logger.getLogger(firmaPDF.class.getName()).log(Level.SEVERE, null, ex);
        } catch (CertificateException ex) {
            ex.printStackTrace();
            //Logger.getLogger(firmaPDF.class.getName()).log(Level.SEVERE, null, ex);
        } catch (FileNotFoundException ex) {
            ex.printStackTrace();
            //Logger.getLogger(firmaPDF.class.getName()).log(Level.SEVERE, null, ex);
        } catch (KeyStoreException ex) {
            ex.printStackTrace();
            //Logger.getLogger(firmaPDF.class.getName()).log(Level.SEVERE, null, ex);
        } catch (GeneralSecurityException ex) {
            ex.printStackTrace();
            //Logger.getLogger(firmaPDF.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            ex.printStackTrace();
            //Logger.getLogger(firmaPDF.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                if (stamper != null){
                    try {
                        stamper.close();
                    } catch (DocumentException ex) {
                       ex.printStackTrace();
                    }
                }
                if (reader != null){
                    reader.close();
                }
            } catch (IOException ex) {
                ex.printStackTrace();
                //Logger.getLogger(firmaPDF.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
    
    /**
     * Método encargado de realizar la firma de un pdf
     * @param rutaEntrada
     * @param rutaSalida
     * @param rutaFirma 
     */
    private void firmaDigitalPDFDNI (String rutaEntrada, String rutaSalida, String rutaFirma){
        PdfReader reader = null;
        PdfStamper stamper = null;
        
    }
    
    public byte getVersion() {
        return 1;
    }

    public String getDocID() {
        return "";
    }
    
    public void feedGrabber(integrisign.IGrabber ig) {
    //BUILD THE HASH INFORMATION OF THE DATA THAT NEEDS TO BOUND TO SIGNATURE OBJECT
    String str = "Nombre y Mensaje";
    ig.grabBytes(str.getBytes());
    ig.finishGrab();
    }
}
